C++实现一个自定义字符串类(string)

您所在的位置:网站首页 char ch=256 C++实现一个自定义字符串类(string)

C++实现一个自定义字符串类(string)

2024-07-13 15:17| 来源: 网络整理| 查看: 265

本博客将详细介绍如何在C++中实现一个自定义的字符串类 string,这个类模仿了标准库中 std::string 的关键功能。这个过程将涵盖从声明到定义的每一步,重点介绍内存管理、操作符重载以及提供一些关键的实现细节。

首先:我们采用函数的声明与定义分离

目的是为了增加代码的可维护性以及提高效率:

1.在vs中,如果我们不实现声明与定义分离,那么编译器会默认认为你当前的函数是内联函数

:内联函数是一种编译器指令,它告诉编译器尝试在每个调用点展开函数体,而不是进行常规的函数调用。 

也就是说每次调用时会直接展开代码,这只适合一些代码量很小但调用机器频繁的函数。所以我们采用函数的声明与定义分离也可以进一步的优化效率。

2.函数声明与定义分离的注意事项和特点

改善编译依赖性:将函数声明放在头文件中,而将实现(定义)放在源文件中,可以减少编译时的依赖关系。当实现改变时,只需重新编译该源文件及其直接依赖,而不需要重新编译包含头文件的所有文件。

封装:通过隐藏实现细节,可以保护数据和实现,减少模块间的耦合。这符合封装的面向对象原则,有助于维护和扩展。

链接考虑:在多个源文件中分散定义的函数只有在最终链接时才会解析。这种分离确保了更好的模块化和错误隔离,尤其是在大型项目中。

避免多重定义:如果在多个源文件中包含相同的函数定义而未进行适当的静态或内联标记,将导致链接错误。正确的声明和定义分离有助于避免这种问题。

类声明和成员变量

首先,我们需要在 my_string 命名空间中定义字符串类的结构。这包括成员变量和函数的声明

#define _CRT_SECURE_NO_WARNINGS #include #include #include namespace my_string { class string { public: typedef char* iterator; typedef const char* const_iterator; public: const_iterator begin() const; const_iterator end() const; iterator begin(); iterator end(); const char* c_str() const; void earse(size_t pos, size_t len = npos); void insert(size_t pos, char ch); void insert(size_t pos, const char* str); void swap(string& s); void clear(); void pushback(char ch); void append(const char* str); void reserve(size_t n); void resize(size_t n, char ch = '\0'); size_t size()const; size_t capacity()const; size_t find(char ch, size_t pos = 0)const; size_t find(char* sub, size_t pos = 0)const; string(const char* str = ""); string(const string& str); ~string(); string& operator=(string tmp); string& operator+=(const char* str); string& operator+=(char ch); bool empty()const; const char& operator[](size_t pos) const { assert(pos < _size); return _str[pos]; } private: char* _str = nullptr; size_t _size = 0; size_t _capacity = 0; public: static const int npos; };

在定义成员变量时我们采用缺省值来增加安全性。

经典的string类问题 浅拷贝 浅拷贝:也称位拷贝,编译器只是将对象中的值拷贝过来 。如果 对象中管理资源 ,最后就会 导致多个对象共 享同一份资源,当一个对象销毁时就会将该资源释放掉,而此时另一些对象不知道该资源已经被释放,以为为 有效,所以当继续对资源进项操作时,就会发生发生了访问违规 深拷贝 如果一个类中涉及到资源的管理,其拷贝构造函数、赋值运算符重载以及析构函数必须要显式给出。一般情 况都是按照深拷贝方式提供。

 也就是说我们如果不显示构造就会用默认的拷贝构造函数,就会出错!

 构造函数和析构函数实现

构造函数初始化字符串,并为字符数组分配内存。我们同时提供了拷贝构造函数和析构函数以处理资源管理:

string::string(const char* str ) :_size(strlen(str)) { _capacity = _size ; _str = new char[_size + 1]; strcpy(_str, str); } string::string(const string& str) { string tmp(str._str); swap(tmp); } string::~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; }

动态内存管理实现

对于内存管理,我们实现了 reserve 和 resize 方法来处理内存分配和调整大小的需求:

void string::reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } void string::resize(size_t n, char ch) { if (n > _size) { reserve(n); std::fill(_str + _size, _str + n, ch); _size = n; } _str[_size] = '\0'; } 操作符重载

操作符重载使得字符串类的对象能以类似于原生数据类型的方式使用:

string& string::operator=(string tmp) { swap(tmp); return *this; } bool operator==(const string& s1, const string& s2) { return strcmp(s1.c_str(), s2.c_str()) == 0; } std::ostream& operator


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3